package pri.hillchen.std.nio.bio.chat;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author:hillchen
 * @DESCRIPTION:
 * @Date: Created in 16:57 2018/3/5 0005.
 */
public class BioServer {
    public static String msgEndFlag = "end";
    public static String clientEndFlag = "bay";

    private final int port;
    private boolean stop = true;
    private ConcurrentHashMap<String,ClientSocketHandel> handels = new ConcurrentHashMap<String, ClientSocketHandel>();

    class ClientSocketHandel implements Runnable{
        private final Socket socket ;
        private final String name;
        private final BufferedReader br;
        private final BufferedWriter bw;
        private boolean conected = true;

        public ClientSocketHandel(Socket socket) throws IOException {
            this.socket = socket;
            this.br = new BufferedReader(new  InputStreamReader(socket.getInputStream(),"utf-8"));
            this.bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"utf-8"));
            this.name = read();
            login();
        }

        public void login() throws IOException {
            String msg = String.format("用户%s登录聊天室。",name);
            System.out.println(msg);
            spreadMsg(name,msg);
            handels.put(name,this);
        }
        public String read() throws IOException {
            StringBuilder sb = new StringBuilder();
            String line ;
            int lineNo = 0;
            while (!msgEndFlag.equals(line = br.readLine())){
                if(lineNo != 0){
                    sb.append("\n");
                }
                sb.append(line);
                lineNo++;
            }
            return sb.toString();
        }
        public void write(String msg) throws IOException {
            bw.write(msg);
            bw.newLine();
            bw.write(msgEndFlag);
            bw.newLine();
            bw.flush();
        }
        public void close(){
            conected = false;
            handels.remove(name);
        }
        @Override
        public void run() {
            try {
                while (!stop && conected){
                    String msg = read();
                    if(clientEndFlag.equals(msg)){
                        close();
                    }else{
                        System.out.println(this.name + " say:" +msg);
                        spreadMsg(name,msg);
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    handels.remove(name);
                    br.close();
                    bw.close();
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void spreadMsg(String name,String word) throws IOException {
        for(Map.Entry<String,ClientSocketHandel> clientSocketHandelEntry : handels.entrySet()){
            String handelName = clientSocketHandelEntry.getKey();
            ClientSocketHandel handel = clientSocketHandelEntry.getValue();
            if(!handelName.equals(name)){
                handel.write(word);
            }
        }
    }


    class ServerThread implements Runnable{
        public void run() {
            ServerSocket  server = null;
            try {
                server = new ServerSocket(port);
                System.out.println("BIO服务已启动，监听端口是：" + port);
                while (!stop){
                    Socket client = server.accept();
                    new Thread(new ClientSocketHandel(client)).start();
                }
                server.close();

            } catch (IOException e) {
                e.printStackTrace();
            }


        }
    }

    public BioServer(int port) {
        this.port = port;
    }

    public void start(){
        this.stop = false;
        new Thread(new ServerThread()).start();
    }

    public void stop(){
        this.stop = true;
    }


    public static void main(String[] args) {
        new BioServer(38080).start();
    }
}
